/*
 ============================================================================
 Name        : Logger.c
 Author      : Grupo Klow
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "Logger.h"

/* Funciones Privadas  */

/* Parte el nombreArchivo en nombre y extension */
void parsearNombreArchivo(char * nombreArchivo, char ** nombre, char ** extension) {
	 unsigned int longitudNombre;
	 unsigned int longitudExtension;

	 char * pch=strrchr(nombreArchivo,'.');

	 //¿El Archivo tiene extension?
	 if (pch != NULL) {
		 longitudNombre=pch-nombreArchivo+1;
		 longitudExtension = strlen(nombreArchivo)-longitudNombre +1;
	 } else {
		 longitudNombre=strlen(nombreArchivo) +1;
		 longitudExtension=1;
	 }

	 *nombre =(char*) malloc (sizeof(char) * longitudNombre);
	 *extension =(char*) malloc (sizeof(char) * longitudExtension);

	 //inicializo
	 memset(*nombre,0,longitudNombre);
	 memset(*extension,0,longitudExtension);

	 strncpy(*nombre,nombreArchivo,longitudNombre-1);
	 strncpy(*extension,pch+sizeof(char),longitudExtension-1);
}

/* Devuelve un puntero a una cadena formada por nombrenumero.extension */
char * generarNombreArchivo(char * nombre, char * extension, unsigned int numero) {
	int temp;
	unsigned int cantidadDigitos=0;
	char * nombreNuevo;
	char * numeroS;
	unsigned int longitudNombre = 0;


	longitudNombre= strlen(extension)+strlen(nombre) +2;

	if (numero > 0) {
		//Obtengo la cantidad de digitos que tiene el numero
		temp=numero;
		while (temp > 0) {
			temp/=10;
			cantidadDigitos++;
		}

		//Paso de int a chr
		numeroS = (char*)malloc (sizeof(char)* (cantidadDigitos+1));
		sprintf(numeroS,"%i",numero);

		longitudNombre+= cantidadDigitos;
	}

	//Pido memoria para el nombre
	nombreNuevo = (char*)malloc(sizeof(char) * longitudNombre);
	//Inicializo
	memset(nombreNuevo,0,longitudNombre);
	//Contaneo
	strcpy(nombreNuevo,"");
	strcat(nombreNuevo,nombre);

	if (numero > 0) {
		strcat(nombreNuevo,numeroS);
		free(numeroS);
	}

	//Si tiene extension concateneo, caso contrario no.
	if (strlen(extension)>0) {
		strcat(nombreNuevo,".");
		strcat(nombreNuevo, extension);
	}

	return nombreNuevo;
}

/* Busca en un archivo especifico la cadena buscando imprimiendo las lineas
que coincidan con la busqueda en salidaResultados */
unsigned int Logger_BuscarEnArchivo(unsigned int parte, char * archivo, char * cadenaBuscada, FILE * salidaResultados) {

	unsigned short int leida;
	unsigned int bytesLeidosTotal;
	unsigned int numeroLinea;
	unsigned int cantidadResultados = 0;

	FILE * archivoOrigen = NULL;

	char * linea = NULL;

	archivoOrigen = fopen(archivo,"r");


	if (archivo != NULL) {

		linea = (char *) malloc(LONGITUD_BUFFER);
		numeroLinea=0;

		while (!feof(archivoOrigen)) {

				leida = 0;
				bytesLeidosTotal=0;

				memset(linea,'\0',LONGITUD_BUFFER);

				while(!leida) {
					fgets(linea+bytesLeidosTotal,LONGITUD_BUFFER,archivoOrigen);
					bytesLeidosTotal=strlen(linea);

					if (feof(archivoOrigen) || linea[bytesLeidosTotal-1]=='\n') {
						leida=1;
					} else {
						linea = (char*)realloc(linea,bytesLeidosTotal + LONGITUD_BUFFER);
					}
				}
				numeroLinea++;

				if (strstr(linea,cadenaBuscada)) {
					fprintf(salidaResultados,"[A%iL%i] %s",parte,numeroLinea,linea);
					cantidadResultados++;
				}
		}

		fclose(archivoOrigen);
		free(linea);
	}

	return cantidadResultados;
}

/* Agrega la fecha del sistema al princio de la cadena */
void agregarFecha(char * cadena) {
	/*Obtiene la fecha actual */
	struct tm * timeinfo;
	time_t rawtime;

	time(&rawtime);
	timeinfo = localtime ( &rawtime );

	strftime(cadena,80,"%d/%m/%Y %X",timeinfo);
	cadena[LONGITUD_FECHA]='\0';

}

/* Obtiene el numero de parte que se debe usar cuando se desborde el archivo
actual */
unsigned int obtenerSigParte(char * nombre, char * extension) {
	FILE * archivoAux;
	char * nombreAux;
	unsigned int parte=1;

	//Genero el posible nombre de archivo
	nombreAux = generarNombreArchivo(nombre,extension,parte);

	//Abro el posible archivo
	archivoAux=fopen(nombreAux,"r");

	while (archivoAux!=NULL) {

		free(nombreAux);
		fclose(archivoAux);

		parte++;

		nombreAux = generarNombreArchivo(nombre,extension,parte);

		archivoAux=fopen(nombreAux,"r");
	}

	free(nombreAux);

	return parte;
}

// Funciones publicas //

void Logger_Cerrar(Logger * logger) {
	free(logger->nombreArchivo);
	free(logger->extension);

	fclose(logger->handleArchivo);
}

void Logger_MostrarInfo(Logger * logger, FILE * salida) {
	fprintf(salida,"Nombre archivo: %s\n", logger->nombreArchivo);
	fprintf(salida,"Extension archivo: %s\n", logger->extension);
	fprintf(salida,"Bytes utilizados: %i\n", logger->bytesUtilizados);
	fprintf(salida,"Capacidad maxima: %i\n", logger->cantidadMaximaBytes);
	fprintf(salida,"Siguiente parte: %i\n", logger->sigParte);
}

void Logger_Insertar(Logger * logger, char * cadena) {

	//Fecha + cadena
	char * texto;
	unsigned int longitud;

	longitud = strlen(cadena) + LONGITUD_FECHA + 3;//+ longitud fecha + 1 espacio + \n + \0

	texto = (char *) malloc(longitud * sizeof(char));

	agregarFecha(texto);
	strcat(texto," ");
	strcat(texto,cadena);
	strcat(texto,"\n");

	//Chequeo si tengo espacio en el archivo para escribir
	if (logger->bytesUtilizados + strlen(texto) > logger->cantidadMaximaBytes) {
		//Sino entra debo cortar el archivo
		//Lo cierro
		fclose(logger->handleArchivo);
		//Lo renombro
		char * nombreNuevo;
		char * nombreOriginal;

		nombreNuevo = generarNombreArchivo(logger->nombreArchivo,logger->extension,logger->sigParte);
		nombreOriginal = generarNombreArchivo(logger->nombreArchivo,logger->extension,0);

		rename(nombreOriginal,nombreNuevo);
		//Genero un nuevo archivo

		logger->handleArchivo=fopen(nombreOriginal,"w+");
		//reseteo el contador
		logger->bytesUtilizados=0;
		//aumento el numero de parte
		logger->sigParte++;
		//libero la memoria pedida para almacenar los nombres
		free(nombreNuevo);
		free(nombreOriginal);
	}
	//Escribo
	fputs(texto,logger->handleArchivo);
	//Actualizo el contador
	logger->bytesUtilizados+=strlen(texto);
	//Libero memoria
	free(texto);
}

unsigned int Logger_Buscar(Logger * logger, char * cadenaBuscada, FILE * salida) {
	//La parte mas vieja esta en nombre1.extension
	unsigned int parte;
	char * archivo;
	unsigned int cantidadResultados = 0;

	for (parte = 1; parte < logger->sigParte; parte++) {
		archivo = generarNombreArchivo(logger->nombreArchivo,logger->extension,parte);
		cantidadResultados+=Logger_BuscarEnArchivo(parte,archivo,cadenaBuscada,salida);
		free(archivo);
	}

	//Busco en el archivo original, que es el mas actual.
	archivo = generarNombreArchivo(logger->nombreArchivo,logger->extension,0);
	cantidadResultados+= Logger_BuscarEnArchivo(0,archivo,cadenaBuscada,salida);
	free(archivo);

	return cantidadResultados;
}

void Logger_Iniciar(Logger * logger, char * nombreArchivo, unsigned int capacidadMaxima) {
	logger->handleArchivo = NULL;
	logger->handleArchivo = fopen(nombreArchivo,"r+");

	//Cargo los datos principales
	parsearNombreArchivo(nombreArchivo,&logger->nombreArchivo,&logger->extension);

	logger->sigParte=1;
	logger->cantidadMaximaBytes=capacidadMaxima;

	// ¿El archivo existe?
	if (logger->handleArchivo!=NULL) {
			//Obtengo el tamanio actual del archivo
			fseek(logger->handleArchivo, 0, SEEK_END);
			logger->bytesUtilizados = ftell(logger->handleArchivo);

			//Obtengo el numero de parte que le sigue en caso de que el archivo se sobrepase
			logger->sigParte = obtenerSigParte(logger->nombreArchivo,logger->extension);
	} else {
		//El archivo no existe, lo creo
		logger->handleArchivo=fopen(nombreArchivo,"w+");
		logger->bytesUtilizados=0;
		logger->sigParte=1;
	}
}

void Logger_Volcar(Logger * logger, char * nombreArchivo) {

	//La parte mas vieja esta en nombre1.extension
	unsigned int parte;
	char * archivo;
	char * bloque;
	FILE * archivoOrigen;
	FILE * archivoDestino;
	unsigned int bytesLeidos;

	archivoDestino = fopen(nombreArchivo,"w");

	bloque = (char *) malloc(LONGITUD_BUFFER);

	for (parte = 1; parte < logger->sigParte; parte++) {

		archivo = generarNombreArchivo(logger->nombreArchivo,logger->extension,parte);
		archivoOrigen = fopen(archivo,"r");

		if (archivo != NULL) {
			while (!feof(archivoOrigen)) {
					bytesLeidos = fread(bloque,1,LONGITUD_BUFFER,archivoOrigen);
					fwrite(bloque,bytesLeidos,1,archivoDestino);
			}

			fclose(archivoOrigen);
		}
		free(archivo);
	}

	//Agrego al archivo destino la información más actual que se encuentra
	// en el archivo principal
	archivo = generarNombreArchivo(logger->nombreArchivo,logger->extension,0);
	archivoOrigen = fopen(archivo,"r");
	if (archivo != NULL) {
		while (!feof(archivoOrigen)) {
				bytesLeidos = fread(bloque,1,LONGITUD_BUFFER,archivoOrigen);
				fwrite(bloque,bytesLeidos,1,archivoDestino);
		}

		fclose(archivoOrigen);
	}
	free(archivo);

	fclose(archivoDestino);
	free(bloque);
}
